home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / bbs / dlmst251.zip / DLMASTER.C next >
C/C++ Source or Header  |  1992-10-09  |  63KB  |  1,901 lines

  1. /**********************************************************************
  2. *  DLMASTER version 2.51  - Make Downloadable List of RBBS files      *
  3. *  compiled with Borland C/C++ v 2.0  using Large memory model        *
  4. *  Copyright (c) 1990-92 by Bob Hampton                               *
  5. *  S3-Tech BBS (703) 451-9509                                         *
  6. *  all rights reserved                                                *
  7. **********************************************************************/
  8.  
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <alloc.h>
  13. #include <dir.h>
  14. #include <dos.h>
  15. #include <conio.h>
  16. #include <process.h>
  17. #include <io.h>
  18. #include <mem.h>
  19. #include <stdarg.h>
  20. #include "doswdw.h"
  21.  
  22. #define FALSE 0
  23. #define TRUE !FALSE
  24. #define OFF 0
  25. #define ON !OFF
  26. #define MAXLINE 161        /* - maximum length of FMS file line   */
  27. #define MAXCATS 10        /* - maximum number of codes/category  */
  28. #define MAXFMS 50        /* - maximum number of FMS directories */
  29. #define SINGLE 1        /* - used in windows to specify single */
  30. #define DOUBLE 2                /*   or double-line borders            */
  31. #define COLOR 1            /* - used for color display mode       */
  32. #define BW 0                /* -  "    "   b&w     "      "        */
  33.  
  34. typedef struct ltag        /* structure for linked-list created   */
  35. {                /* in initial read of FMS file(s):     */
  36.     char lname[13];            /* - name of file                   */
  37.     long lsize,            /* - size of file (in bytes)        */
  38.          ldate,            /* - date of file                   */
  39.          lpos;            /* - position of description in FMS */
  40.     int  lfms;            /* - FMS array index                */
  41.     char lcode[4];            /* - category code of file          */
  42.     struct ltag *lnext;        /* - pointer to next node           */
  43. } LDATA;
  44.  
  45.  
  46. typedef struct            /* structure for temporary files.  Same as  */
  47. {                /* LDATA but without category code or next  */
  48.     char tname[13];        /* node pointer.                            */
  49.     long tsize,
  50.          tdate,
  51.          tpos;
  52.     int  tfms;
  53. } TDATA;
  54.  
  55. typedef    struct ptag        /* structure for print buffer   */
  56. {                /*    linked-list.  Includes:   */
  57.     char prtline[MAXLINE];    /*  - line buffer               */
  58.     struct ptag *pnext;    /*  - pointer to next node      */
  59. } PDATA;
  60.  
  61.  
  62. typedef struct            /* structure for config record: */
  63. {
  64.     char fmsname[MAXPATH],        /* - FMS filename               */
  65.          dcatname[MAXPATH],        /* - DIR.CAT filename           */
  66.          outname[MAXPATH],        /* - output file path/name      */
  67.          bbsname[65],        /* - name of BBS                */
  68.          sorttype,            /* - A)lpha or D)ate sort       */
  69.          revsort,            /* - flag for reverse sort      */
  70.          hdrname[MAXPATH],        /* - name of header file        */
  71.          ftrname[MAXPATH],        /* - name of footer file        */
  72.          zippath[MAXPATH];        /* - path to compression util   */
  73. } CNFGREC;
  74.  
  75. typedef struct dtag        /* structure of linked-list for */
  76. {                /* info from DIR.CAT file:      */
  77.     char dname[9],            /* - name of directory          */
  78.          dcode[MAXCATS][4],        /* - category code              */
  79.          ddesc[65];            /* - directory description      */
  80.     struct dtag *dnext;        /* - pointer to next node       */
  81. } DCATINFO;
  82.  
  83.  
  84. typedef struct ctag        /* structure of linked-list for valid */
  85. {                /* category codes, includes:          */
  86.     char code[4];        /*    - code                        */
  87.     struct ctag *cnext;    /*    - pointer to next node        */
  88. } CATCODE;
  89.  
  90.  
  91. typedef struct            /* structure for array of info     */
  92. {                /* about FMS file(s):              */
  93.     char name[MAXPATH];        /* - FMS filename                  */
  94.     int top;            /* - if \FMS TOP used in this file */
  95. } FMSFILE;
  96.  
  97. typedef struct             /* structure containing info about */
  98. {                /* current window:                 */
  99.     int left,            /* - left coordinate               */
  100.         top,            /* - top coordinate                */
  101.         right,            /* - right coordinate              */
  102.         bottom,            /* - bottom coordinate             */
  103.         fore,            /* - normal foreground color       */
  104.         back,            /* - normal background color       */
  105.         hifore,            /* - hilight foreground color      */
  106.         hiback,            /* - hilight background color      */
  107.         bstyle,            /* - border style                  */
  108.         bcolor,            /* - border color                  */
  109.         shadow;            /* - flag for 3-D shadow           */
  110. } WININFO;
  111.  
  112. void  make_wallpaper   (unsigned char c, int fore, int back);
  113. void  make_window      (WININFO *win);
  114. void  read_cnfgfile    (char *cnfgname, CNFGREC *crec, WININFO *win);
  115. void  read_dircatfile  (char *dcatname, DCATINFO **dfirst, WININFO *win);
  116. int   create_cats      (DCATINFO *dnode, CATCODE **cfirst);
  117. void  make_temps       (CATCODE *cnode, WININFO *win);
  118. void  searchfms        (char *fmsname, FMSFILE *fmsdata, int *linelength);
  119. void  readfms          (FMSFILE *fmsdata, int num_cats, WININFO *win, CATCODE *cfirst, int *totalfiles, long *totalbytes, int *zip_fms_index, long *zip_fms_pos, char *zipname);
  120. void  make_sortfiles   (LDATA *lnode[], WININFO *win, CATCODE *cnode);
  121. void  process_list     (DCATINFO *dnode, CATCODE *cnode, CNFGREC *crec, int linelength, int totalfiles, long totalbytes, FMSFILE *fmsdata, WININFO *win);
  122. void  print_buffer     (FILE *outfile, PDATA *pnode);
  123. void  print_listheader (CNFGREC *crec, FILE *outfile);
  124. void  print_dirheader  (DCATINFO *dnode, int tempfiles, long tempbytes, FILE *outfile);
  125. void  print_listfooter (int totalfiles, long totalbytes, FILE *outfile);
  126. void  printfile        (char *filename, char *message, FILE *outfile);
  127. void  make_zip         (char *zippath, char *textname, WININFO *win);
  128. int   afcompare        (TDATA huge **elem1, TDATA huge **elem2);
  129. int   arcompare        (TDATA huge **elem1, TDATA huge **elem2);
  130. int   dfcompare        (TDATA huge **elem1, TDATA huge **elem2);
  131. int   drcompare        (TDATA huge **elem1, TDATA huge **elem2);
  132. void  cursor           (int cmnd);
  133. int   check_catcode    (char *code, CATCODE *cnode);
  134. void  fail             (char *message, char *filename);
  135. int   set_colors       (WININFO *header, WININFO *center, WININFO *bottom);
  136. void  clear_status     (WININFO *win);
  137.  
  138. extern unsigned _stklen = 49152;    /* set stack size to 48K           */
  139.  
  140. void main (int argc, char **argv)
  141. {
  142.     CNFGREC crec;            /* DLMASTER config file info       */
  143.     DCATINFO *dfirst = NULL;    /* head pointer for directory list */
  144.     CATCODE *cfirst = NULL;        /*  "      "     "  catcodes   "   */
  145.     FMSFILE fmsdata[MAXFMS];    /* array of FMS file info          */
  146.     char cnfgname[MAXPATH];        /* DLMASTER config file path/name  */
  147.     int linelength = 0,        /* FMS line length                 */
  148.         totalfiles,            /* total number of files           */
  149.         num_cats,            /* number of categories            */
  150.         dispmode,            /* current display mode            */
  151.         zip_fms_index,        /* index to FMS file containing
  152.                        description of Zip file         */
  153.         i;                /* work variable                   */
  154.     long totalbytes,        /* total number of bytes           */
  155.          zip_fms_pos;        /* byte position of Zipfile descr.
  156.                        in FMS file containing descr.   */
  157.     WININFO header,            /* info for top window             */
  158.         center,            /*  "    "  center "               */
  159.         bottom;            /*  "    "  bottom "               */
  160.  
  161.     switch (argc)
  162.     {
  163.         case 1:            /* no config file specified in command line */
  164.             strcpy (cnfgname, "DLMASTER.CFG");
  165.             break;
  166.         case 2:            /* config file specified in command line */
  167.             strcpy (cnfgname, *(argv + 1));
  168.             break;
  169.         default:
  170.             fprintf (stderr, "\nInvalid command line\n\n");
  171.             fprintf (stderr, "Usage: DLMASTE2 <config file>\n");
  172.             exit(1);
  173.     }
  174.  
  175.     /***************************************************
  176.     *  determine the display mode (color or b&w), and  *
  177.     *  set the colors for the windows accordingly.     *
  178.     ***************************************************/
  179.     dispmode = set_colors (&header, ¢er, &bottom);
  180.  
  181.     /************************************************************
  182.     *  set text to white-on-black, clear the screen, paint the  *
  183.     *  wallpaper, create the top window, and display the title  *
  184.     ************************************************************/
  185.     cursor (OFF);
  186.     textattr (7);
  187.     clrscr();
  188.     if (dispmode == COLOR)
  189.         make_wallpaper('.', LIGHTGRAY, BLUE);
  190.     make_window (&header);
  191.     cputs ("  DLMASTER version 2.51                       (c) 1990-92 by Bob Hampton");
  192.  
  193.     /**********************************
  194.     *  create the bottom window, and  *
  195.     *  read the DLMASTER config file  *
  196.     **********************************/
  197.     make_window (&bottom);
  198.     read_cnfgfile (cnfgname, &crec, &bottom);
  199.  
  200.     /**********************************
  201.     *  create the middle window, and  *
  202.     *  read the DIR.CAT file.  Create *
  203.     *  list of categories, and create *
  204.     *  the temp files.                *
  205.     **********************************/
  206.     make_window (¢er);
  207.     read_dircatfile (crec.dcatname, &dfirst, ¢er);
  208.     num_cats = create_cats (dfirst, &cfirst);
  209.     make_temps (cfirst, ¢er);
  210.  
  211.     /****************************************
  212.     *  create array of info on FMS file(s)  *
  213.     ****************************************/
  214.     searchfms (crec.fmsname, fmsdata, &linelength);
  215.  
  216.     /***************************************************
  217.     *  read the FMS file(s) and create the temp files  *
  218.     ***************************************************/
  219.     readfms (fmsdata, num_cats, ¢er, cfirst, &totalfiles, &totalbytes, &zip_fms_index, &zip_fms_pos, crec.outname);
  220.  
  221.     /*************************************
  222.     *  create the output text file from  *
  223.     *  the temp and FMS files            *
  224.     *************************************/
  225.     process_list (dfirst, cfirst, &crec, linelength,
  226.               totalfiles, totalbytes, fmsdata, ¢er);
  227.  
  228.     /***************************************
  229.     *  create the ZIP file, if requested,  *
  230.     *  deleting the text file afterwards   *
  231.     ***************************************/
  232.     if (strcmp (crec.zippath, ""))
  233.         make_zip (crec.zippath, crec.outname, ¢er);
  234.  
  235.     /****************************************
  236.     *  set screen to white-on-black, clear  *
  237.     *  the screen, and restore the cursor   *
  238.     ****************************************/
  239.     textattr (7);
  240.     window (1,1,80,25);
  241.     clrscr();
  242.     cursor (ON);
  243. }
  244.  
  245.  
  246.  
  247. void read_cnfgfile (char *cnfgname, CNFGREC *crec, WININFO *win)
  248. {
  249. /*******************************************************************
  250. *  This function will read the config file specified in *cnfgname  *
  251. *  and modify the config file record *crec to contain information  *
  252. *  from the configuration file.                                    *
  253. *******************************************************************/
  254.  
  255.     FILE *cnfgfile;            /* pointer to config file */
  256.     char buffer[MAXLINE];        /* buffer for file read   */
  257.  
  258.     /*********************
  259.     *  open config file  *
  260.     *********************/
  261.     if ((cnfgfile = fopen (cnfgname, "r")) == NULL)
  262.         fail ("Error opening config file", cnfgname);
  263.  
  264.     /********************************
  265.     *  read name of first FMS file  *
  266.     ********************************/
  267.     fgets (buffer, MAXLINE, cnfgfile);
  268.     strcpy (crec->fmsname, strtok (buffer, "\n"));
  269.  
  270.     /******************************
  271.     *  read name of DIR.CAT file  *
  272.     ******************************/
  273.     fgets (buffer, MAXLINE, cnfgfile);
  274.     strcpy (crec->dcatname, strtok (buffer, "\n"));
  275.  
  276.     /*****************************
  277.     *  read name of output file  *
  278.     *****************************/
  279.     fgets (buffer, MAXLINE, cnfgfile);
  280.     strcpy (crec->outname, strtok (buffer, "\n"));
  281.  
  282.     /*********************
  283.     *  read name of BBS  *
  284.     *********************/
  285.     fgets (buffer, MAXLINE, cnfgfile);
  286.     strcpy (crec->bbsname, strtok (buffer, "\n"));
  287.  
  288.  
  289.     /****************************
  290.     *  read sort type (A or D)  *
  291.     ****************************/
  292.     crec->sorttype = fgetc (cnfgfile);
  293.     fgetc (cnfgfile);
  294.  
  295.     /***************************
  296.     *  read reverse sort flag  *
  297.     ***************************/
  298.     crec->revsort = fgetc (cnfgfile);
  299.     fgetc (cnfgfile);
  300.  
  301.     /*****************************************
  302.     *  optionally, read name of header file  *
  303.     *****************************************/
  304.     if (fgets (buffer, MAXLINE, cnfgfile) != NULL && *buffer != '\n')
  305.         strcpy (crec->hdrname, strtok (buffer, "\n"));
  306.     else
  307.         strcpy (crec->hdrname, "");
  308.  
  309.     /*****************************************
  310.     *  optionally, read name of footer file  *
  311.     *****************************************/
  312.     if (fgets (buffer, MAXLINE, cnfgfile) != NULL && *buffer != '\n')
  313.         strcpy (crec->ftrname, strtok (buffer, "\n"));
  314.     else
  315.         strcpy (crec->ftrname, "");
  316.  
  317.     /********************************
  318.     *  optionally, read PKZIP path  *
  319.     ********************************/
  320.     if (fgets (buffer, MAXLINE, cnfgfile) != NULL && *buffer != '\n')
  321.         strcpy (crec->zippath, strtok (buffer, "\n"));
  322.     else
  323.         strcpy (crec->zippath, "");
  324.  
  325.     /***********************************
  326.     *  close config file, and display  *
  327.     *  runtime parameters in window    *
  328.     ***********************************/
  329.     fclose (cnfgfile);
  330.     gotoxy (3,1);
  331.     cputs ("sort type - ");
  332.     textcolor (win->hifore);
  333.     if (toupper (crec->sorttype) == 'A')
  334.         cputs ("Alpha");
  335.     else
  336.         cputs ("Date");
  337.  
  338.     textcolor (win->fore);
  339.     gotoxy (30,1);
  340.     cputs ("reverse sort - ");
  341.     textcolor (win->hifore);
  342.     if (toupper (crec->revsort) == 'Y')
  343.         cputs ("Yes");
  344.     else
  345.         cputs ("No");
  346.  
  347.     textcolor (win->fore);
  348.     gotoxy (59,1);
  349.     cputs ("auto ZIP - ");
  350.     textcolor (win->hifore);
  351.     if (strcmp (crec->zippath, ""))
  352.         cputs ("Yes");
  353.     else
  354.         cputs ("No");
  355.     textcolor (win->fore);
  356. }
  357.  
  358.  
  359.  
  360. void read_dircatfile (char *dcatname, DCATINFO **dfirst, WININFO *win)
  361. {
  362. /*********************************************************************
  363. *  This function will read the DIR.CAT file specified in *dcatname   *
  364. *  and will modify the pointer *dfirst to point to the first node    *
  365. *  in the linked-list of info about the file categories.   It will   *
  366. *  also create the temp files for the categories using the category  *
  367. *  name, and will save 0 at the beginning of each file as the count  *
  368. *  for the number of files in that category.                         *
  369. *********************************************************************/
  370.  
  371.     FILE *dirfile;            /*  pointer to DIR.CAT file   */
  372.     DCATINFO *dnode,        /*  pointer to current node   */
  373.          *dprev;        /*    "     "  previous  "    */
  374.     char buffer[MAXLINE],        /*  buffer for file read      */
  375.          tempcat[65],        /*  work buffer for cat desc  */
  376.          *temp;            /*  work pointer              */
  377.     int  i;                /*  work variable             */
  378.  
  379.     /********************************
  380.     *  display directory file name  *
  381.     ********************************/
  382.     gotoxy (16,3);
  383.     cputs ("Reading directory file: ");
  384.     textattr (win->hifore + (win->hiback << 4));
  385.     cprintf ("%s", dcatname);
  386.     textattr (win->fore + (win->back << 4));
  387.     clreol();
  388.  
  389.     /********************************************
  390.     *  open DIR.CAT file, allocate first node,  *
  391.     *  and set head of linked-list              *
  392.     ********************************************/
  393.     if ((dirfile = fopen (dcatname, "r")) == NULL)
  394.         fail ("Error opening category file", dcatname);
  395.     dnode = (DCATINFO *) malloc (sizeof (DCATINFO));
  396.     if (dnode == NULL)
  397.         fail ("Unable to create","dnode");
  398.     *dfirst = dnode;
  399.  
  400.     /***************************************
  401.     *  for each line in the DIR.CAT file,  *
  402.     ***************************************/
  403.     while (fgets (buffer, MAXLINE, dirfile) != NULL)
  404.     {
  405.         /******************************************
  406.         *  get directory name from buffer, strip  *
  407.         *  next seperating comma.                 *
  408.         ******************************************/
  409.         strcpy (dnode->dname, strtok (buffer, "\""));
  410.         temp = strtok (NULL, "\"");
  411.  
  412.         /**************************************
  413.         *  get category code(s) from buffer,  *
  414.         *  and strip next separating comma.   *
  415.         **************************************/
  416.         strcpy (tempcat, strtok (NULL, "\""));
  417.         temp = strtok (NULL, "\"");
  418.  
  419.         /******************************************
  420.         *  get directory description from buffer  *
  421.         ******************************************/
  422.         strcpy (dnode->ddesc, strtok (NULL, "\""));
  423.  
  424.  
  425.         /*********************************************
  426.         *  separate category code(s) from tempcat[]  *
  427.         *********************************************/
  428.         i = 0;
  429.         strcpy (dnode->dcode[i++], strtok (tempcat, ", "));
  430.         while (i < MAXCATS && (temp = strtok (NULL, ", ")) != NULL)
  431.             strcpy (dnode->dcode[i++], temp);
  432.         if (i != MAXCATS)
  433.             strcpy (dnode->dcode[i], "###");
  434.  
  435.         /*****************************************************
  436.         *  create the next node, set previous node pointer   *
  437.         *  to the current node, and set the current pointer  *
  438.         *  to new node                                       *
  439.         *****************************************************/
  440.         dnode->dnext = (DCATINFO *) malloc (sizeof (DCATINFO));
  441.         if (dnode->dnext == NULL)
  442.             fail ("Unable to create","dnode->dnext");
  443.         dprev = dnode;
  444.         dnode = dnode->dnext;
  445.     }
  446.  
  447.     /*******************************************************
  448.     *  set previous node's pointer-to-next to NULL, free   *
  449.     *  the unneeded node from memory, close DIR.CAT file,  *
  450.     *  and return the number of categories                 *
  451.     *******************************************************/
  452.     dprev->dnext = NULL;
  453.     free (dnode);
  454.     fclose (dirfile);
  455. }
  456.  
  457.  
  458.  
  459. int create_cats (DCATINFO *dnode, CATCODE **cfirst)
  460. {
  461. /***********************************************************************
  462. *  This function will create a linked-list of valid category codes by  *
  463. *  scanning through the dcodes in the linked-list of dnode info.  It   *
  464. *  will eliminate any duplicate codes, making a list we can use for    *
  465. *  tempfile maintenance.                                               *
  466. ***********************************************************************/
  467.  
  468.     CATCODE *cnode = NULL,
  469.         *cprev = NULL;
  470.     int catfound = FALSE,
  471.         num_cats = 0,
  472.         i;
  473.  
  474.     /*********************************
  475.     *  for each node in linked-list  *
  476.     *  of DIR.CAT entries            *
  477.     *********************************/
  478.     while (dnode)
  479.     {
  480.         /****************************
  481.         *  scan each category code  *
  482.         ****************************/
  483.         for (i = 0; i < MAXCATS && strcmp (dnode->dcode[i], "###"); i++)
  484.         {
  485.             cnode = *cfirst;
  486.             while (cnode && catfound == FALSE)
  487.             {
  488.                 if (strcmp (dnode->dcode[i], cnode->code) == 0)
  489.                     catfound = TRUE;
  490.                 cprev = cnode;
  491.                 cnode = cnode->cnext;
  492.             }
  493.  
  494.             /***********************************
  495.             *  if code not already in list of  *
  496.             *  codes, add to list              *
  497.             ***********************************/
  498.             if (catfound == FALSE)
  499.             {
  500.                 num_cats++;
  501.                 cnode = (CATCODE *) malloc (sizeof (CATCODE));
  502.                 if (cnode == NULL)
  503.                     fail ("Unable to create","cnode->cnext");
  504.                 if (cprev)
  505.                     cprev->cnext = cnode;
  506.                 cnode->cnext = NULL;
  507.                 strcpy (cnode->code, dnode->dcode[i]);
  508.                 if (*cfirst == NULL)
  509.                     *cfirst = cnode;
  510.             }
  511.             catfound = FALSE;
  512.         }
  513.     dnode = dnode->dnext;
  514.     }
  515.  
  516.     /*******************************
  517.     *  return the number of codes  *
  518.     *******************************/
  519.     return (num_cats);
  520. }
  521.  
  522.  
  523.  
  524. void make_temps (CATCODE *cnode, WININFO *win)
  525. {
  526. /**********************************************************
  527. *  This function creates the temp files from info in the  *
  528. *  cnode linked-list of category names.                   *
  529. **********************************************************/
  530.  
  531.     FILE *tempfile;
  532.     char tempname[MAXPATH];
  533.     int tempfiles = 0,
  534.         i;
  535.  
  536.     /******************************
  537.     *  for every category code..  *
  538.     ******************************/
  539.     while (cnode)
  540.     {
  541.         /**************************************************
  542.         *  make tempfilename and display it.  Open file,  *
  543.         *  write 0 to beginning of file (for number of    *
  544.         *  tempfiles), and close tempfile                 *
  545.         **************************************************/
  546.         strcpy (tempname, "$DLTEMP.");
  547.         strcat (tempname, cnode->code);
  548.         gotoxy (16,3);
  549.         cputs ("Creating temporary file: ");
  550.         textattr (win->hifore + (win->hiback << 4));
  551.         cprintf ("%s", tempname);
  552.         textattr (win->fore + (win->back << 4));
  553.         clreol();
  554.  
  555.         if ( (tempfile = fopen (tempname, "wb")) == NULL)
  556.             fail ("Unable to open tempfile - ", tempname);
  557.         fwrite (&tempfiles, 2, 1, tempfile);
  558.         fclose (tempfile);
  559.         cnode = cnode->cnext;
  560.     }
  561. }
  562.  
  563.  
  564.  
  565.  
  566. void searchfms (char *fmsname, FMSFILE *fmsdata, int *linelength)
  567. {
  568. /******************************************************************
  569. *  This function will read file information from the FMS file(s), *
  570. *  starting with the filename passed in *fmsname.  It will        *
  571. *  modify the *fmsdata array to hold info about each of the       *
  572. *  FMS files, and will set *linelength to the length of the       *
  573. *  FMS line.                                                      *
  574. ******************************************************************/
  575.  
  576.  
  577.     int i = 0,               /*  work variable for indexing  */
  578.         chain = TRUE;        /*  flag for chained FMS        */
  579.     char buffer[MAXLINE],        /*  buffer for file read        */
  580.          *work,            /*  work pointer                */
  581.          *fmsarg;            /*  pointer to FMS header arg   */
  582.     FILE *fp;            /*  pointer to FMS file         */
  583.  
  584.     /***********************
  585.     *  for each FMS file,  *
  586.     ***********************/
  587.     while (chain && i < MAXFMS)
  588.     {
  589.  
  590.         /***********************
  591.         *  set flags to FALSE  *
  592.         ***********************/
  593.         chain = FALSE;
  594.         (fmsdata + i)->top = FALSE;
  595.  
  596.         /*****************************************
  597.         *  copy FMS filename to array, open FMS  *
  598.         *  file, and read first line             *
  599.         *****************************************/
  600.         strcpy ((fmsdata + i)->name, fmsname);
  601.         if ((fp = fopen ((fmsdata + i)->name, "r")) == NULL)
  602.             fail ("Unable to open FMS file", fmsname);
  603.         fgets (buffer, MAXLINE, fp);
  604.  
  605.         /*********************************
  606.         *  if linelength is not already  *
  607.         *  set, then set it              *
  608.         *********************************/
  609.         if (*linelength == 0)
  610.             *linelength = strlen (buffer) + 1;
  611.  
  612.  
  613.         /***************************
  614.         *  if line is FMS header,  *
  615.         ***************************/
  616.         if (strncmp (buffer, "\\FMS", 4) == 0)
  617.         {
  618.             /**************************************
  619.             *  set work pointer to next argument  *
  620.             *  and get next argument              *
  621.             **************************************/
  622.             work = strtok (buffer, "\n");
  623.             work += 4;
  624.             fmsarg = strtok (work, " ");
  625.  
  626.             /*********************************
  627.             *  for each remaining argument,  *
  628.             *********************************/
  629.             while (fmsarg)
  630.             {
  631.                 /***************************************
  632.                 *  if "CH()" command, get the name of  *
  633.                 *  the file to chain to, and set the   *
  634.                 *  chain flag to TRUE                  *
  635.                 ***************************************/
  636.                 if (strncmp (fmsarg, "CH(", 3) == 0)
  637.                 {
  638.                     fmsarg += 3;
  639.                     strcpy (fmsname, fmsarg);
  640.                     fmsname[strlen(fmsarg)-1] = '\0';
  641.                     chain = TRUE;
  642.                 }
  643.  
  644.                 /*******************************************
  645.                 *  otherwise, if argument is TOP command,  *
  646.                 *  set the TOP flag to TRUE                *
  647.                 *******************************************/
  648.                 else if (strcmp (fmsarg, "TOP") == 0)
  649.                     (fmsdata + i)->top = TRUE;
  650.  
  651.                 /**************************
  652.                 *  get the next argument  *
  653.                 **************************/
  654.                 fmsarg = strtok (NULL, " ");
  655.             }
  656.         }
  657.  
  658.         /***************************
  659.         *  close the FMS file and  *
  660.         *  increment the index     *
  661.         ***************************/
  662.         fclose (fp);
  663.         i++;
  664.     }
  665.  
  666.     /**********************************
  667.     *  if the FMS array is not full,  *
  668.     *  set the next filename to NULL  *
  669.     ***********************************/
  670.     if (i < MAXFMS)
  671.         strcpy ( (fmsdata + i)->name, "");
  672. }
  673.  
  674.  
  675. void readfms (FMSFILE *fmsdata, int num_cats, WININFO *win, CATCODE *cfirst, int *totalfiles, long *totalbytes, int *zip_fms_index, long *zip_fms_pos, char *outname)
  676. {
  677. /***************************************************************************
  678. *  This function will read the FMS file(s) listed in the *fmsdata          *
  679. *  array and builds an array of linked-lists of file info using the LDATA  *
  680. *  structure.  This array will be filled to memory, then purged and        *
  681. *  refilled as necessary to finish reading the FMS file(s).  At each       *
  682. *  purge, the temp files will be written to using the make_sortfiles()     *
  683. *  function.                                                               *
  684. ***************************************************************************/
  685.  
  686.  
  687.     LDATA **lnode,        /* array of pointers to current node    */
  688.           **lfirst;        /*   "   "     "      " beg. of arrays  */
  689.     char *buffer,        /* buffer for file read          */
  690.          namebuff[14],    /* buffer for name/ext parsing   */
  691.          zipname[MAXPATH],    /* ZIP name to look for in FMS   */
  692.          lext[9],        /* extension for file name       */
  693.          testcode[4],    /* test buffer for category code */
  694.          tempdate[9],    /* work variable for file date   */
  695.          tempsize[9];    /* work variable for file size   */
  696.     FILE *fp;        /* pointer to FMS file           */
  697.     int i,            /* work variable for indexing    */
  698.         lndx,        /* index to lnode array          */
  699.         fndx = 0;        /* index to FMS array            */
  700.     long fpos;        /* file position                 */
  701.  
  702.  
  703.     buffer = (char *) malloc (MAXLINE);
  704.  
  705.     /**************************************************
  706.     *  strip extension from output text file name to  *
  707.     *  yield name to search for in FMS file(s) to     *
  708.     *  locate current file/position of description    *
  709.     *  for the ZIPfile                                *
  710.     **************************************************/
  711.     strcpy (zipname, outname);
  712.     strtok (strupr (zipname), ".");
  713.  
  714.     /******************************************************
  715.     *  allocate first nodes for arrays, set variable and  *
  716.     *  array values, and display template in window       *
  717.     ******************************************************/
  718.     lnode = (LDATA **) malloc (sizeof (LDATA *) * num_cats);
  719.     lfirst = (LDATA **) malloc (sizeof (LDATA *) * num_cats);
  720.     *totalfiles = 0;
  721.     *totalbytes = 0L;
  722.     for (i = 0; i < num_cats; i++)
  723.     {
  724.         lnode[i] = NULL;
  725.         lfirst[i] = NULL;
  726.     }
  727.     gotoxy (50,5);
  728.     cputs ("Total files:");
  729.     gotoxy (50,6);
  730.     cputs ("Total bytes:");
  731.  
  732.     /********************************
  733.     *  for each file in FMS array,  *
  734.     ********************************/
  735.     while ( strcmp( (fmsdata + fndx)->name, "") && fndx < MAXFMS)
  736.     {
  737.         /******************************************
  738.         *  set file position,  display filename,  *
  739.         *  and seek to beginning of file          *
  740.         ******************************************/
  741.         fpos = 0L;
  742.         gotoxy (16,3);
  743.         cputs ("Reading FMS file: ");
  744.         textattr (win->hifore + (win->hiback << 4));
  745.         cprintf ("%s", (fmsdata + fndx)->name);
  746.         textattr (win->fore + (win->back << 4));
  747.         clreol();
  748.         if ((fp = fopen ((fmsdata + fndx)->name, "r")) == NULL)
  749.             fail ("Unable to open FMS file", (fmsdata+fndx)->name);
  750.         fseek (fp, 0L, SEEK_SET);
  751.  
  752.         /*******************************
  753.         *  for each line of FMS file,  *
  754.         *******************************/
  755.         while (fgets (buffer, MAXLINE, fp) != NULL)
  756.         {
  757.             textcolor (win->hifore);
  758.  
  759.             /*********************************
  760.             *  if filename present in line,  *
  761.             *********************************/
  762.             if (strchr (" \\*", (int) *buffer) == NULL)
  763.             {
  764.  
  765.                 /**********************************************
  766.                 *  if this line contains the current Zipfile  *
  767.                 *  description, set the FMS array index and   *
  768.                 *  file position into the holding variables   *
  769.                 *  so we can use them later to update the     *
  770.                 *  description.  Otherwise, process as a      *
  771.                 *  normal file.                               *
  772.                 **********************************************/
  773.                 if (strncmp (zipname, buffer, strlen (zipname)) == 0)
  774.                 {
  775.                     *zip_fms_index = fndx;
  776.                     *zip_fms_pos = fpos;
  777.                 }
  778.                 else
  779.                 {
  780.                     /************************************
  781.                     *  test for security level of file  *
  782.                     ************************************/
  783. /* (remember - want to add */        if (*buffer == '=')
  784. /*  true security process- */            buffer++;
  785. /*  ing later...)          */
  786.                     /*************************************
  787.                     *  put category code in work buffer  *
  788.                     * and strip from end of buffer       *
  789.                     *************************************/
  790.                     strncpy (testcode, buffer+strlen(buffer)-4, 3);
  791.                     testcode[3] = '\0';
  792.                     buffer[strlen(buffer)-4] = '\0';
  793.  
  794.                     /****************************
  795.                     *  if valid category code,  *
  796.                     ****************************/
  797.                     if ( (i = check_catcode (testcode, cfirst)) != -1)
  798.                     {
  799.                         /******************************
  800.                         *  set index for lnode array  *
  801.                         ******************************/
  802.                         lndx = i;
  803.  
  804.                         /*********************************
  805.                         *  if less than 1K memory left,  *
  806.                         *********************************/
  807.                         if (coreleft() < 1000L)
  808.                         {
  809.                             /**********************************
  810.                             *  append info to tempfiles,      *
  811.                             *  freeing memory in the process, *
  812.                             *  and redisplay the template     *
  813.                             **********************************/
  814.                             make_sortfiles (lfirst, win, cfirst);
  815.                             for (i = 0; i < num_cats; i++)
  816.                             {
  817.                                 lnode[i] = NULL;
  818.                                 lfirst[i] = NULL;
  819.                             }
  820.  
  821.  
  822.                             gotoxy (16,3);
  823.                             cputs ("Reading FMS file: ");
  824.                             textattr (win->hifore + (win->hiback << 4));
  825.                             cprintf ("%s", (fmsdata + fndx)->name);
  826.                             textattr (win->fore + (win->back << 4));
  827.                             clreol();
  828.                         }
  829.  
  830.                         /*************************************
  831.                         *  if first node of this cat empty,  *
  832.                         *  allocate the first node           *
  833.                         *************************************/
  834.                         if (lnode[lndx] == NULL)
  835.                         {
  836.                             lnode[lndx] = (LDATA *) malloc (sizeof (LDATA));
  837.                             if (lnode[lndx] == NULL)
  838.                                 fail ("Unable to create", "lnode");
  839.                             lfirst[lndx] = lnode[lndx];
  840.                         }
  841.  
  842.                         /******************************************
  843.                         *  otherwise, allocate the next node and  *
  844.                         *  set current node pointer to next node  *
  845.                         ******************************************/
  846.                         else
  847.                         {
  848.                             lnode[lndx]->lnext = (LDATA *) malloc (sizeof (LDATA));
  849.                             if (lnode[lndx]->lnext == NULL)
  850.                                 fail ("Unable to create", "lnode");
  851.                             lnode[lndx] = lnode[lndx]->lnext;
  852.                         }
  853.  
  854.                         /*********************************************
  855.                         *  set file position and next node pointer,  *
  856.                         *  and copy category code from work buffer   *
  857.                         *********************************************/
  858.                         lnode[lndx]->lpos = fpos;
  859.                         lnode[lndx]->lnext = NULL;
  860.                         strcpy (lnode[lndx]->lcode, testcode);
  861.  
  862.                         /******************************************
  863.                         *  get file name/ext in work buffer, and  *
  864.                         *  strip from beginning of line buffer    *
  865.                         ******************************************/
  866.                         strncpy (namebuff, buffer, 13);
  867.                         namebuff[13] = '\0';
  868.                         strrev (buffer);
  869.                         buffer[strlen(buffer)-13] = '\0';
  870.                         strrev (buffer);
  871.  
  872.                         /*********************************************
  873.                         *  get filename, and extension (if there is  *
  874.                         *  one) from work buffer, and reformat it    *
  875.                         *********************************************/
  876.                         strcpy (lnode[lndx]->lname, strtok (namebuff, " ."));
  877.                         strcpy (lext, strtok (NULL, " ."));
  878.                         if (strcmp (lext, ""))
  879.                         {
  880.                             strcat (lnode[lndx]->lname, ".");
  881.                             strcat (lnode[lndx]->lname, lext);
  882.                         }
  883.  
  884.                         /**************************************
  885.                         *  get filesize, add to total bytes   *
  886.                         **************************************/
  887.                         strcpy (tempsize, strtok (buffer, " "));
  888.                         lnode[lndx]->lsize = atol (tempsize);
  889.                         *totalbytes += lnode[lndx]->lsize;
  890.  
  891.                         /************************************************
  892.                         *  get file date and convert to numeric YYMMDD  *
  893.                         ************************************************/
  894.                         strcpy (tempdate, strtok (NULL, " -"));
  895.                         strcat (tempdate, strtok (NULL, "-"));
  896.                         strcat (tempdate, strtok (NULL, " "));
  897.                         lnode[lndx]->ldate = atol (tempdate);
  898.                         strncpy (tempdate, "0000", 4);
  899.                         lnode[lndx]->ldate = (atol (tempdate) * 10000) + (lnode[lndx]->ldate / 100);
  900.  
  901.                         /****************************
  902.                         *  set index for FMS array  *
  903.                         ****************************/
  904.                         lnode[lndx]->lfms = fndx;
  905.  
  906.                         /**************************************
  907.                         *  increment and display total files  *
  908.                         *  and total bytes every              *
  909.                         **************************************/
  910.                         (*totalfiles)++;
  911.                         gotoxy (63,5);
  912.                         cprintf ("%d", *totalfiles);
  913.                         gotoxy (63,6);
  914.                         cprintf ("%ld", *totalbytes);
  915.                     }
  916.                 }
  917.             }
  918.  
  919.             /**********************
  920.             *  get file position  *
  921.             **********************/
  922.             fpos = ftell (fp);
  923.         }
  924.  
  925.         /******************************
  926.         *  close current FMS file and *
  927.         *  increment FMS array index  *
  928.         ******************************/
  929.         fclose (fp);
  930.         fndx++;
  931.         textcolor (win->fore);
  932.     }
  933.  
  934.     /*********************************************
  935.     *  append info to tempfiles, freeing memory  *
  936.     *********************************************/
  937.     make_sortfiles (lfirst, win, cfirst);
  938.  
  939.  
  940.  
  941. }
  942.  
  943.  
  944.  
  945. void make_sortfiles (LDATA *lnode[], WININFO *win, CATCODE *cnode)
  946. {
  947. /********************************************************************************
  948. *  This function will append file entries to the temporary files created for    *
  949. *  each category.  It will access the array of LDATA structures for the file    *
  950. *  info, but will use a TDATA structure for writing to the files.  It will      *
  951. *  access the DCATINFO structure to get the category names, in order to access  *
  952. *  the temporary files.  It will also free the memory used by the ldata[]       *
  953. *  array, so that more files than can fit in memory may be processed.           *
  954. ********************************************************************************/
  955.  
  956.  
  957.     FILE *tempfile;            /* pointer to current temp file  */
  958.     int i = 0,            /* work variable for indexing    */
  959.         tempfiles;            /* number of files in temp file  */
  960.     char tempname[MAXPATH];        /* name of temp file             */
  961.     LDATA *lprev;            /* pointer to previous lnode     */
  962.  
  963.  
  964.     /*******************************
  965.     *  display template in window  *
  966.     *******************************/
  967.     textattr (win->fore + (win->back << 4));
  968.     gotoxy (16, 3);
  969.     cprintf ("Appending to tempfile: ");
  970.  
  971.     /****************************
  972.     *  for each category code,  *
  973.     ****************************/
  974.     while (cnode)
  975.     {
  976.         /***************************************
  977.         *  set tempfile name,  and display it  *
  978.         ***************************************/
  979.         strcpy (tempname, "$DLTEMP.");
  980.         strcat (tempname, cnode->code);
  981.         textattr (win->hifore + (win->hiback << 4));
  982.         gotoxy (39, 3);
  983.         cprintf ("%s", tempname);
  984.         textattr (win->fore + (win->back << 4));
  985.         clreol();
  986.  
  987.         /*************************************************
  988.         *  open tempfile, read current number of files,  *
  989.         *  and seek to end for appending                 *
  990.         *************************************************/
  991.         if ((tempfile = fopen (tempname, "r+b")) == NULL)
  992.             fail ("Unable to open tempfile", tempname);
  993.         fread (&tempfiles, 2, 1, tempfile);
  994.         fseek (tempfile, 0L, SEEK_END);
  995.  
  996.         /**************************************************
  997.         *  for each node in this category's linked-list,  *
  998.         *  increment the file count, write the node info, *
  999.         *  go to the next node, and free the previous     *
  1000.         *  node from memory                               *
  1001.         **************************************************/
  1002.         while (lnode[i] && strcmp (lnode[i]->lname, ""))
  1003.         {
  1004.             tempfiles++;
  1005.             fwrite (lnode[i], sizeof (TDATA), 1, tempfile);
  1006.             lprev = lnode[i];
  1007.             lnode[i] = lnode[i]->lnext;
  1008.             free (lprev);
  1009.         }
  1010.  
  1011.         /*****************************************
  1012.         *  seek to beginning of file, write new  *
  1013.         *  filecount, and close the file         *
  1014.         *****************************************/
  1015.         fseek (tempfile, 0L, SEEK_SET);
  1016.         fwrite (&tempfiles, 2, 1, tempfile);
  1017.         fclose (tempfile);
  1018.  
  1019.         /**************************************
  1020.         *  increment the category index, and  *
  1021.         *  go to next category                *
  1022.         **************************************/
  1023.         i++;
  1024.         cnode = cnode->cnext;
  1025.     }
  1026. }
  1027.  
  1028.  
  1029.  
  1030. void process_list (DCATINFO *dnode, CATCODE *cnode, CNFGREC *crec, int linelength, int totalfiles, long totalbytes, FMSFILE *fmsdata, WININFO *win)
  1031. {
  1032. /****************************************************************************
  1033. *  The heart of the beast!  This function creates the downloadable file     *
  1034. *  listing from the temp files created previously, along with the FMS       *
  1035. *  files listed in the FMSFILE array (*fmsdata).   Once all records for a   *
  1036. *  category  are loaded into memory, they can be sorted either by filename  *
  1037. *  or by date, in ascending or descending order.                            *
  1038. ****************************************************************************/
  1039.  
  1040.  
  1041.     DCATINFO *dfirst,        /* pointer to head of linked-list       */
  1042.          *dprev;        /*    "    "  previous dnode            */
  1043.     CATCODE *cprev;            /*    "    "  previous cnode            */
  1044.     TDATA huge *tdata;        /*    "    "  array of tempfile records */
  1045.     TDATA huge *tfirst;        /*    "    "  first element of above    */
  1046.     TDATA huge *twork;        /*    "    used when enlarging array    */
  1047.     TDATA **t_array;        /* array of pointers to be sorted       */
  1048.     TDATA **t_first;        /* pointer to first element of above    */
  1049.     FILE *sortfile,            /* pointer to current tempfile  */
  1050.          *outfile,            /* pointer to output file       */
  1051.          *fp;            /* pointer to FMS file          */
  1052.     int count,            /* loop control counter         */
  1053.         loop,            /* flag for extended descr.     */
  1054.         tempfiles,            /* number of files in tempfile  */
  1055.         tworkfiles,            /* number used to enlarge array */
  1056.         i,                /* work variable for indexing   */
  1057.         x;                /* work variable for counting   */
  1058.     long rcnt,            /* number of bytes to backup    */
  1059.                     /*   in file (reverse count)    */
  1060.          prev = 1,            /* position to seek to in file  */
  1061.                     /*   when backing up            */
  1062.          tempbytes;            /* number of bytes in category  */
  1063.     char sfilename[MAXPATH],    /* temp filename                */
  1064.          buffer[MAXLINE],        /* buffer for read/write        */
  1065.          graph[51],            /* graph to display             */
  1066.          *buffptr;            /* buffer pointer               */
  1067.     PDATA *pnode = NULL,        /* linked-list pointers         */
  1068.           *pfirst = NULL;
  1069.  
  1070.     /*************************************************
  1071.     *  open output file, print the list header and,  *
  1072.     *  optionally, the user's header                 *
  1073.     *************************************************/
  1074.     if ((outfile = fopen (crec->outname, "w")) == NULL)
  1075.         fail ("Unable to open output file", crec->outname);
  1076.     print_listheader (crec, outfile);
  1077.     if (strcmp (crec->hdrname, "") != 0)
  1078.         printfile (crec->hdrname, "header", outfile);
  1079.  
  1080.     /******************************************************
  1081.     *  set head pointer to list of categories, calculate  *
  1082.     *  rcnt from linelength, and display template         *
  1083.     ******************************************************/
  1084.     dfirst = dnode;
  1085.     rcnt = (long) linelength * 2;
  1086.     gotoxy (12,1);
  1087.     cputs ("0   .    .    .    .    50   .    .    .    .   100");
  1088.     gotoxy (1,3);
  1089.     clreol();
  1090.     gotoxy (5, 4);
  1091.     cputs ("Processing output for directory:");
  1092.     gotoxy (5, 5);
  1093.     cputs ("files this directory:");
  1094.     gotoxy (5, 6);
  1095.     cputs ("bytes this directory:");
  1096.  
  1097.     /***********************
  1098.     *  for each category,  *
  1099.     ***********************/
  1100.     while (dnode)
  1101.     {
  1102.         tdata = tfirst = NULL;
  1103.         t_array = t_first = NULL;
  1104.  
  1105.         /*********************************
  1106.         *  initialize and display graph  *
  1107.         *********************************/
  1108.         textattr (win->fore + (win->back << 4));
  1109.         gotoxy (12,2);
  1110.         strcpy (graph, "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░");
  1111.         cputs (graph);
  1112.  
  1113.         /**************************************************
  1114.         *  set byte count to 0 and display category name  *
  1115.         **************************************************/
  1116.         tempbytes = 0L;
  1117.         textattr (win->hifore + (win->hiback << 4));
  1118.         gotoxy (38,4);
  1119.         cprintf ("%s", dnode->dname);
  1120.         textattr (win->hifore + (win->back << 4));
  1121.         clreol();
  1122.  
  1123.         /**********************************
  1124.         *  for each code in category....  *
  1125.         **********************************/
  1126.         i = tempfiles = 0;
  1127.         while (i < MAXCATS && strcmp (dnode->dcode[i], "###"))
  1128.         {
  1129.             /******************************************
  1130.             *  set tempfile name, open tempfile, read *
  1131.             *  number of files, and add to total.     *
  1132.             ******************************************/
  1133.             strcpy (sfilename, "$DLTEMP.");
  1134.             strcat (sfilename, dnode->dcode[i]);
  1135.             if ((sortfile = fopen (sfilename, "rb")) != NULL)
  1136.                 fread (&tworkfiles, 2, 1, sortfile);
  1137.             tempfiles += tworkfiles;
  1138.             fclose (sortfile);
  1139.             i++;
  1140.         }
  1141.  
  1142.         /********************************
  1143.         *  if this category has files,  *
  1144.         ********************************/
  1145.         if (tempfiles != 0)
  1146.         {
  1147.             /***********************
  1148.             *  allocate the array  *
  1149.             ***********************/
  1150.  
  1151.             tdata = (TDATA huge *) farmalloc ((unsigned long) sizeof (TDATA) * tempfiles);
  1152.             if (tdata == NULL)
  1153.                 fail ("Unable to allocate","tdata");
  1154.  
  1155.             /***********************************
  1156.             *  read tempfile(s) to fill array  *
  1157.             ***********************************/
  1158.             i = tempfiles = 0;
  1159.             while (i < MAXCATS && strcmp (dnode->dcode[i], "###"))
  1160.             {
  1161.                 /******************************************
  1162.                 *  set tempfile name, open tempfile, and  *
  1163.                 *  read number of files                   *
  1164.                 ******************************************/
  1165.                 strcpy (sfilename, "$DLTEMP.");
  1166.                 strcat (sfilename, dnode->dcode[i]);
  1167.                 if ((sortfile = fopen (sfilename, "rb")) != NULL)
  1168.                     fread (&tworkfiles, 2, 1, sortfile);
  1169.                 tempfiles += tworkfiles;
  1170.                 twork = tdata;
  1171.                 for (x=0; x < (tempfiles - tworkfiles); x++, twork++);
  1172.                 fread ((TDATA *) twork, sizeof (TDATA), tworkfiles, sortfile);
  1173.                 fclose (sortfile);
  1174.                 i++;
  1175.             }
  1176.         }
  1177.  
  1178.  
  1179.         /*******************************
  1180.         *  display number of files in  *
  1181.         *  this category               *
  1182.         *******************************/
  1183.         gotoxy (27,5);
  1184.         cprintf ("%d     ", tempfiles);
  1185.  
  1186.  
  1187.         /************************************************
  1188.         *  If there are files for this category, copy   *
  1189.         *  address of array elements into pointer array *
  1190.         *  in order to sort pointers                    *
  1191.         ************************************************/
  1192.         if (tempfiles != 0)
  1193.         {
  1194.             tfirst = tdata;
  1195.             t_array = (TDATA **) malloc (sizeof (TDATA *) * tempfiles);
  1196.             if (t_array == NULL)
  1197.                 fail ("Unable to create array","t_array");
  1198.             t_first = t_array;
  1199.             count = 0;
  1200.             while (count < tempfiles)
  1201.             {
  1202.                 *t_array = (TDATA *) tdata;
  1203.                 tempbytes += tdata->tsize;
  1204.                 tdata++;
  1205.                 count++;
  1206.                 t_array++;
  1207.             }
  1208.  
  1209.             /********************************************
  1210.             *  set array pointers back to beginning of  *
  1211.             *  array, and sort the array                *
  1212.             ********************************************/
  1213.             tdata = tfirst;
  1214.             t_array = t_first;
  1215.  
  1216.             if (toupper (crec->sorttype) == 'A')
  1217.             {
  1218.                 if (toupper (crec->revsort) == 'N')
  1219.                     qsort ((void *) t_array, tempfiles, sizeof (TDATA *), (int (*) (const void *, const void *)) afcompare);
  1220.                 else
  1221.                     qsort ((void *) t_array, tempfiles, sizeof (TDATA *), (int (*) (const void *, const void *)) arcompare);
  1222.             }
  1223.             else
  1224.             {
  1225.                 if (toupper (crec->revsort) == 'N')
  1226.                     qsort ((void *) t_array, tempfiles, sizeof (TDATA *), (int (*) (const void *, const void *)) dfcompare);                else
  1227.                     qsort ((void *) t_array, tempfiles, sizeof (TDATA *), (int (*) (const void *, const void *)) drcompare);
  1228.             }
  1229.         }
  1230.  
  1231.         /**************************************************
  1232.         *  display the number of bytes in this category,  *
  1233.         *  and print the directory header to output file  *
  1234.         **************************************************/
  1235.         gotoxy (27,6);
  1236.         cprintf ("%ld      ", tempbytes);
  1237.         print_dirheader (dnode, tempfiles, tempbytes, outfile);    /* print directory header */
  1238.  
  1239.         /*******************************
  1240.         *  for each element of array,  *
  1241.         *******************************/
  1242.         count = 0;
  1243.         while (count < tempfiles)
  1244.         {
  1245.             /*************************
  1246.             *  update graph display  *
  1247.             *************************/
  1248.             textattr (win->fore + (win->back << 4));
  1249.             if (count > 0)
  1250.             {
  1251.                 x = count*100/tempfiles;
  1252.                 for (i=0; i <= x/2; graph[i++]='█');
  1253.                 gotoxy (12, 2);
  1254.                 cputs (graph);
  1255.             }
  1256.  
  1257.             /******************
  1258.             *  set loop flag  *
  1259.             ******************/
  1260.             loop = TRUE;
  1261.  
  1262.             /****************************************
  1263.             *  open appropriate FMS file and        *
  1264.             *  seek to proper position in FMS file  *
  1265.             *  and read first line of description   *
  1266.             ****************************************/
  1267.             if ((fp = fopen ((fmsdata + (*t_array)->tfms)->name, "r")) == NULL)
  1268.                 fail ("Unable to open FMS file", (fmsdata + (*t_array)->tfms)->name);
  1269.             fseek (fp, (*t_array)->tpos, SEEK_SET);
  1270.             fgets (buffer, MAXLINE, fp);
  1271.  
  1272.             /*******************************************
  1273.             *  copy buffer to print buffer, stripping  *
  1274.             *  category code and extra spaces at end   *
  1275.             *******************************************/
  1276.             strrev (buffer);
  1277.             buffptr = buffer;
  1278.             buffptr += 4;
  1279.             while (*buffptr == ' ')
  1280.                 buffptr++;
  1281.             strrev (buffptr);
  1282.             strcat (buffptr, "\n");
  1283.             if (pfirst)
  1284.             {
  1285.                 pnode->pnext = (PDATA *) calloc (1, sizeof (PDATA));
  1286.                 pnode = pnode->pnext;
  1287.             }
  1288.             else
  1289.             {
  1290.                 pnode = (PDATA *) calloc (1, sizeof (PDATA));
  1291.                 pfirst = pnode;
  1292.             }
  1293.             strcpy (pnode->prtline, buffptr);
  1294.  
  1295.             /***********************************
  1296.             *  if < 1K memory left, print the  *
  1297.             *  buffer to the file, freeing     *
  1298.             *  memory in the process           *
  1299.             ***********************************/
  1300.             if (coreleft() < 1000L)
  1301.             {
  1302.                 clear_status (win);
  1303.                 print_buffer (outfile, pfirst);
  1304.                 pfirst = pnode = NULL;
  1305.                 clear_status (win);
  1306.             }
  1307.  
  1308.             /**************************************
  1309.             *  keep reading lines to see if part  *
  1310.             *  of extended description            *
  1311.             **************************************/
  1312.             while (loop)
  1313.             {
  1314.                 /******************************************
  1315.                 *  if FMS TOP is FALSE, seek to previous  *
  1316.                 *  line and check if not before file      *
  1317.                 *  beginning, otherwise turn loop off     *
  1318.                 ******************************************/
  1319.                 if (fmsdata[(*t_array)->tfms].top == FALSE)
  1320.                 {
  1321.                     prev = ftell (fp) - rcnt;
  1322.                     if (prev >= 0)
  1323.                         fseek (fp, prev, SEEK_SET);
  1324.                     else
  1325.                         loop = FALSE;
  1326.                 }
  1327.  
  1328.                 /***************************
  1329.                 *  if loop is still TRUE,  *
  1330.                 ***************************/
  1331.                 if (loop)
  1332.                 {
  1333.                     /***************************
  1334.                     *  if not at end of file,  *
  1335.                     ***************************/
  1336.                     if (fgets (buffer, MAXLINE, fp) != NULL)
  1337.                     {
  1338.                         /****************************
  1339.                         *  if next line is part of  *
  1340.                         *  extended description,    *
  1341.                         ****************************/
  1342.                         if (*buffer == ' ')
  1343.                         {
  1344.                             /************************************
  1345.                             *  if not line from RBBSWHO merge,  *
  1346.                             ************************************/
  1347.                             if (strncmp (buffer, "  Uploaded", 10))
  1348.                             {
  1349.  
  1350.                                 /*******************************************
  1351.                                 *  copy buffer to print buffer, stripping  *
  1352.                                 *  final period and extra spaces at end    *
  1353.                                 *******************************************/
  1354.                                 strrev (buffer);
  1355.                                 buffptr = buffer;
  1356.                                 buffptr += 4;
  1357.                                 while (*buffptr == ' ')
  1358.                                     buffptr++;
  1359.                                 strrev (buffptr);
  1360.                                 strcat (buffptr, "\n");
  1361.                                 if (pfirst)
  1362.                                 {
  1363.                                     pnode->pnext = (PDATA *) calloc (1, sizeof (PDATA));
  1364.                                     pnode = pnode->pnext;
  1365.                                 }
  1366.                                 else
  1367.                                 {
  1368.                                     pnode = (PDATA *) calloc (1, sizeof (PDATA));
  1369.                                     pfirst = pnode;
  1370.                                 }
  1371.                                 strcpy (pnode->prtline, buffptr);
  1372.  
  1373.                                 /***********************************
  1374.                                 *  if < 1K memory left, print the  *
  1375.                                 *  buffer to the file, freeing     *
  1376.                                 *  memory in the process           *
  1377.                                 ***********************************/
  1378.                                 if (coreleft() < 1000L)
  1379.                                 {
  1380.                                     print_buffer (outfile, pfirst);
  1381.                                     pfirst = pnode = NULL;
  1382.                                 }
  1383.                             }
  1384.                         }
  1385.  
  1386.                         /****************************************
  1387.                         *  if not part of extended description, *
  1388.                         *  break the loop                       *
  1389.                         ****************************************/
  1390.                         else
  1391.                             loop = FALSE;
  1392.                     }
  1393.  
  1394.                     /******************************
  1395.                     *  if at EOF, break the loop  *
  1396.                     ******************************/
  1397.                     else
  1398.                         loop = FALSE;
  1399.                 }
  1400.             }
  1401.  
  1402.             /****************************************
  1403.             *  close current FMS file and           *
  1404.             *  increment array pointer and counter  *
  1405.             ****************************************/
  1406.             fclose (fp);
  1407.             t_array++;
  1408.             count++;
  1409.         }
  1410.  
  1411.         /********************************
  1412.         *  if not 0 files in category,  *
  1413.         *  free arrays from memory      *
  1414.         ********************************/
  1415.         if (tempfiles != 0)
  1416.         {
  1417.             free (t_first);        /* clear pointer array     */
  1418.             free ((TDATA *)tfirst);            /* clear array from memory */
  1419.         }
  1420.  
  1421.         /************************
  1422.         *  flush buffer and     *
  1423.         *  go to next category  *
  1424.         ************************/
  1425.         print_buffer (outfile, pfirst);
  1426.         pfirst = pnode = NULL;
  1427.         dnode = dnode->dnext;
  1428.         textcolor (win->fore);
  1429.     }
  1430.  
  1431.     /*********************************
  1432.     *  flush remaining print buffer  *
  1433.     *********************************/
  1434.     clear_status (win);
  1435.     print_buffer (outfile, pfirst);
  1436.     pfirst = pnode = NULL;
  1437.     clear_status (win);
  1438.     textattr (win->hifore + (win->back << 4));
  1439.  
  1440.     /******************************************
  1441.     *  print user's footer (optional), print  *
  1442.     *  list footer, and close output file     *
  1443.     ******************************************/
  1444.     if (strcmp (crec->ftrname, "") != 0)
  1445.         printfile (crec->ftrname, "footer", outfile);
  1446.     print_listfooter (totalfiles, totalbytes, outfile);
  1447.     fclose (outfile);
  1448.  
  1449.     /**************************************
  1450.     *  clear screen, and display message  *
  1451.     *  while deleting temp files and      *
  1452.     *  clearing cnode list from memory    *
  1453.     **************************************/
  1454.     clrscr();
  1455.     gotoxy (20,3);
  1456.     cputs ("Erasing Temp Files.....");
  1457.     while (cnode)
  1458.     {
  1459.         strcpy (sfilename, "$DLTEMP.");
  1460.         strcat (sfilename, cnode->code);
  1461.         unlink (sfilename);
  1462.         cprev = cnode;
  1463.         cnode = cnode->cnext;
  1464.         free (cprev);
  1465.     }
  1466.  
  1467.  
  1468.     /*********************************
  1469.     *  clear dnode list from memory  *
  1470.     *********************************/
  1471.     dnode = dfirst;
  1472.     while (dnode)
  1473.     {
  1474.         dprev = dnode;
  1475.         dnode = dnode->dnext;
  1476.         free (dprev);
  1477.     }
  1478. }
  1479.  
  1480.  
  1481.  
  1482. void print_buffer (FILE *outfile, PDATA *pnode)
  1483. {
  1484.     PDATA *pprev;
  1485.  
  1486.     while (pnode)
  1487.     {
  1488.         fputs (pnode->prtline, outfile);
  1489.         pprev = pnode;
  1490.         pnode = pnode->pnext;
  1491.         free (pprev);
  1492.     }
  1493. }
  1494.  
  1495.  
  1496.  
  1497.  
  1498. void print_listheader (CNFGREC *crec, FILE *outfile)
  1499. {
  1500.     int i,
  1501.         lead;
  1502.     char *ampm = "am",
  1503.          prtdate[40];
  1504.     struct date pdate;
  1505.     struct time ptime;
  1506.  
  1507.     getdate (&pdate);
  1508.     gettime (&ptime);
  1509.     if (ptime.ti_hour > 12)
  1510.     {
  1511.         ptime.ti_hour -= 12;
  1512.         strcpy (ampm, "pm");
  1513.     }
  1514.     sprintf (prtdate, "Last Updated %d/%d/%d at %d:%02d%s",
  1515.          pdate.da_mon, pdate.da_day, pdate.da_year, ptime.ti_hour, ptime.ti_min, ampm);
  1516.     fprintf (outfile, "┌─────────────────────────────────────────────────────────────────────────────┐\n");
  1517.     fprintf (outfile, "│");
  1518.     lead = (78 - strlen(crec->bbsname)) / 2;
  1519.     for (i = 0; i < lead; i++)
  1520.         fprintf (outfile, " ");
  1521.     fprintf (outfile, "%s", crec->bbsname);
  1522.     for (i = 1; i < (78 - lead- strlen(crec->bbsname)); i++)
  1523.         fprintf (outfile, " ");
  1524.     fprintf (outfile, "│\n");
  1525.     fprintf (outfile, "│                        Master List of Download Files                        │\n");
  1526.     fprintf (outfile, "│                                                                             │\n");
  1527.     fprintf (outfile, "│");
  1528.     lead = (78 - strlen(prtdate)) / 2;
  1529.     for (i = 1; i < lead; i++)
  1530.         fprintf (outfile, " ");
  1531.     fprintf (outfile, "%s", prtdate);
  1532.     for (i = 0; i < (78 - lead - strlen(prtdate)); i++)
  1533.         fprintf (outfile, " ");
  1534.     fprintf (outfile, "│\n");
  1535.     fprintf (outfile, "└─────────────────────────────────────────────────────────────────────────────┘\n");
  1536. }
  1537.  
  1538.  
  1539.  
  1540. void print_dirheader (DCATINFO *dnode, int tempfiles, long tempbytes, FILE *outfile)
  1541. {
  1542.     fprintf (outfile, "\n┌───────────────┬─────────────────────────────────────────────────────────────┐\n");
  1543.     fprintf (outfile, "│ %-13s │ %-59s │\n", dnode->dname, dnode->ddesc);
  1544.     fprintf (outfile, "├───────────────┴─────────────────────────────────────────────────────────────┤\n");
  1545.     fprintf (outfile, "│  Number of files: %-4d                          Number of bytes: %-9ld  │\n", tempfiles, tempbytes);
  1546.     fprintf (outfile, "├────────────┬────────┬────────┬──────────────────────────────────────────────┤\n");
  1547.     fprintf (outfile, "│ Filename   │  Size  │  Date  │  Description                                 │\n");
  1548.     fprintf (outfile, "└────────────┴────────┴────────┴──────────────────────────────────────────────┘\n");
  1549. }
  1550.  
  1551.  
  1552. void print_listfooter (int totalfiles, long totalbytes, FILE *outfile)
  1553. {
  1554.     fprintf (outfile, "\n┌─────────────────────────────────────────────────────────────────────────────┐\n");
  1555.     fprintf (outfile, "│       Total number of files in all directories:  %-5d                      │\n", totalfiles);
  1556.     fprintf (outfile, "│       Total number of bytes in all directories:  %-10ld                 │\n", totalbytes);
  1557.     fprintf (outfile, "└─────────────────────────────────────────────────────────────────────────────┘\n");
  1558. }
  1559.  
  1560.  
  1561. void printfile (char *filename, char *message, FILE *outfile)
  1562. {
  1563.     FILE *infile;
  1564.     char buffer[MAXLINE];
  1565.  
  1566.     gotoxy (16,2);
  1567.     cprintf ("Adding %s file to output....", message);
  1568.     clreol();
  1569.     if ((infile = fopen (filename, "r")) == NULL)
  1570.         fail ("Unable to open file", filename);
  1571.     while (fgets (buffer, MAXLINE, infile) != NULL)        /* read file to end   */
  1572.         fputs (buffer, outfile);
  1573.     fclose (infile);
  1574. }
  1575.  
  1576.  
  1577.  
  1578. int afcompare (TDATA huge **elem1, TDATA huge **elem2)
  1579. {
  1580.     return (strcmp ((*elem1)->tname, (*elem2)->tname));
  1581. }
  1582.  
  1583.  
  1584. int arcompare (TDATA huge **elem1, TDATA huge **elem2)
  1585. {
  1586.     return (strcmp ((*elem2)->tname, (*elem1)->tname));
  1587. }
  1588.  
  1589.  
  1590. int dfcompare (TDATA huge **elem1, TDATA huge **elem2)
  1591. {
  1592.     int retval;
  1593.  
  1594.     if ((*elem1)->tdate == (*elem2)->tdate)
  1595.         retval = strcmp ((*elem1)->tname, (*elem2)->tname);
  1596.     else
  1597.         retval = ((*elem1)->tdate < (*elem2)->tdate) ? -1 : 1;
  1598.     return (retval);
  1599. }
  1600.  
  1601.  
  1602. int drcompare (TDATA huge **elem1, TDATA huge **elem2)
  1603. {
  1604.     int retval;
  1605.  
  1606.     if ((*elem1)->tdate == (*elem2)->tdate)
  1607.         retval = strcmp ((*elem2)->tname, (*elem1)->tname);
  1608.     else
  1609.         retval = ((*elem2)->tdate < (*elem1)->tdate) ? -1 : 1;
  1610.     return (retval);
  1611. }
  1612.  
  1613.  
  1614.  
  1615. void make_wallpaper (unsigned char c, int fore, int back)
  1616. {
  1617.     int far *video,
  1618.         row,
  1619.         col,
  1620.         attr,
  1621.         i;
  1622.     struct text_info tinfo;
  1623.  
  1624.     gettextinfo (&tinfo);
  1625.     if (tinfo.currmode == MONO)
  1626.         video = (int far *) 0xB0000000;
  1627.     else
  1628.         video = (int far *) 0xB8000000;
  1629.     attr = fore + (back << 4);
  1630.     textattr (attr);
  1631.     clrscr();
  1632.     for (row = 0; row < 25; row += 2)
  1633.         if (row % 4 == 0)
  1634.             for (col = 0; col < 80; col += 10)
  1635.                 *(video + (row * 80) + col + 2) = c | (attr << 8);
  1636.         else
  1637.             for (col = 5; col < 80; col += 10)
  1638.                 *(video + (row * 80) + col + 2) = c | (attr << 8);
  1639. }
  1640.  
  1641.  
  1642. void make_window (WININFO *win)
  1643. {
  1644.     int row, col, attr, pos,
  1645.         far *video;
  1646.     char *savetext;
  1647.     struct text_info tinfo;
  1648.     struct
  1649.     {
  1650.         int upleft, upright, dnleft, dnright,
  1651.             vert, horiz;
  1652.     } border[3] = {{ 32,  32,  32,  32,  32,  32},
  1653.                {218, 191, 192, 217, 179, 196},
  1654.                {201, 187, 200, 188, 186, 205}};
  1655.  
  1656.     gettextinfo (&tinfo);
  1657.     if (tinfo.currmode == MONO)
  1658.         video = (int far *) 0xB0000000;
  1659.     else
  1660.         video = (int far *) 0xB8000000;
  1661.     attr = (win->bcolor + (win->back << 4)) << 8;
  1662.     *(video + (win->top - 1) * 80 + win->left - 1) = border[win->bstyle].upleft | attr;
  1663.     *(video + (win->top - 1) * 80 + win->right - 1) = border[win->bstyle].upright | attr;
  1664.     *(video + (win->bottom - 1) * 80 + win->left - 1) = border[win->bstyle].dnleft | attr;
  1665.     *(video + (win->bottom - 1) * 80 + win->right - 1) = border[win->bstyle].dnright | attr;
  1666.     for (col = win->left; col < win->right-1; col++)
  1667.     {
  1668.         *(video + ((win->top-1)*80) + col) = border[win->bstyle].horiz | attr;
  1669.         *(video + ((win->bottom-1)*80) + col) = border[win->bstyle].horiz | attr;
  1670.     }
  1671.     for (row = win->top; row < win->bottom-1; row++)
  1672.     {
  1673.         *(video + (row * 80) + win->left-1) = border[win->bstyle].vert | attr;
  1674.         *(video + (row * 80) + win->right-1) = border[win->bstyle].vert | attr;
  1675.     }
  1676.     window (win->left+1, win->top+1, win->right-1, win->bottom-1);
  1677.     textattr (win->fore + (win->back << 4));
  1678.     clrscr();
  1679.     if (win->shadow)
  1680.     {
  1681.         for (row = win->top; row <= win->bottom; row++)
  1682.         {
  1683.             *(video + (row * 80) + win->right) &= 0x00FF;
  1684.             *(video + (row * 80) + win->right) |= (DARKGRAY + (BLACK << 4)) << 8;
  1685.             *(video + (row * 80) + win->right + 1) &= 0x00FF;
  1686.             *(video + (row * 80) + win->right + 1) |= (DARKGRAY + (BLACK << 4)) << 8;
  1687.         }
  1688.         for (col = win->left+1; col <= win->right; col++)
  1689.         {
  1690.             *(video + (win->bottom * 80) + col) &= 0x00FF;
  1691.             *(video + (win->bottom * 80) + col) |= (DARKGRAY + (BLACK << 4)) << 8;
  1692.         }
  1693.     }
  1694. }
  1695.  
  1696.  
  1697.  
  1698.  
  1699. void make_zip (char *zippath, char *textname, WININFO *win)
  1700. {
  1701.     char command[MAXLINE],
  1702.          zipname[MAXPATH],
  1703.          *ziputil;
  1704.     int x,
  1705.         y,
  1706.         i;
  1707.  
  1708.     /******************************************************
  1709.     *  copy the path\filename of the compression utility  *
  1710.     *  into the ziputil variable and extract the name     *
  1711.     *  of the compression utility.                        *
  1712.     ******************************************************/
  1713.     ziputil = (char *) malloc (MAXPATH);
  1714.     strcpy (ziputil, zippath);
  1715.     strrev (ziputil);
  1716.     strtok (ziputil, "\\");
  1717.     strrev (ziputil);
  1718.     strtok (ziputil, ".");
  1719.  
  1720.     strcpy (zipname, textname);
  1721.     strtok (zipname, ".");
  1722.  
  1723.     strcpy (command, zippath);
  1724.     if (strcmp (strupr (ziputil), "PKZIP") == 0)
  1725.         strcat (command, " -a ");
  1726.     else
  1727.         strcat (command, " a ");
  1728.     strcat (command, zipname);
  1729.     strcat (command, " ");
  1730.     strcat (command, textname);
  1731.     strcat (command, " > NUL");
  1732.     DoDosWdw (win->left+1, win->top+1,win->right-1,win->bottom-1,
  1733.           (win->fore + (win->back << 4)),command);
  1734.  
  1735.     if (strcmp (strupr (ziputil), "PKZIP") == 0)
  1736.         strcat (zipname, ".ZIP");
  1737.     else if (strcmp (strupr (ziputil), "LHA") == 0)
  1738.         strcat (zipname, ".LZH");
  1739.     else if (strcmp (strupr (ziputil), "ARJ") == 0)
  1740.         strcat (zipname, ".ARJ");
  1741.  
  1742.     if (access (zipname, 0))
  1743.         fail ("Unable to create ZIP file: ", zipname);
  1744.     else
  1745.         unlink (textname);
  1746. }
  1747.  
  1748.  
  1749.  
  1750. void cursor (int cmnd)
  1751. {
  1752.     union REGS regs;
  1753.     int attribute;
  1754.  
  1755.     regs.h.ah = 0x01;
  1756.     if (cmnd == OFF)
  1757.         attribute = 0x01;
  1758.     else
  1759.         attribute = 0x00;
  1760.     regs.h.ch = attribute << 5 | 6;
  1761.     regs.h.cl = 7;
  1762.     int86 (0x10, ®s, ®s);
  1763. }
  1764.  
  1765.  
  1766. int check_catcode (char *code, CATCODE *cnode)
  1767. {
  1768.     int i,
  1769.         cndx = 0;
  1770.  
  1771.     if (strcmp (code, "***") == 0)
  1772.         cndx = -1;
  1773.     else
  1774.         while (cnode && strcmp (cnode->code, code))
  1775.         {
  1776.             cndx++;
  1777.             cnode = cnode->cnext;
  1778.         }
  1779.     if (cnode == NULL)
  1780.         cndx = -1;
  1781.     return (cndx);
  1782. }
  1783.  
  1784.  
  1785.  
  1786. void fail (char *message, char *filename)
  1787. {
  1788.     clrscr();
  1789.     gotoxy (16,2);
  1790.     cprintf ("%s %s ", message, filename);
  1791.     gotoxy (16,3);
  1792.     perror ("");
  1793.     textattr (7);
  1794.     cursor (ON);
  1795.     exit (1);
  1796. }
  1797.  
  1798.  
  1799. int set_colors (WININFO *header, WININFO *center, WININFO *bottom)
  1800. {
  1801.     int dispmode;
  1802.     struct text_info t_info;
  1803.  
  1804.         header->left = 2;
  1805.         header->top = 2;
  1806.         header->right = 77;
  1807.         header->bottom = 4;
  1808.         center->left = 2;
  1809.         center->top = 9;
  1810.         center->right = 77;
  1811.         center->bottom = 16;
  1812.         bottom->left = 2;
  1813.         bottom->top = 20;
  1814.         bottom->right = 77;
  1815.         bottom->bottom = 22;
  1816.  
  1817.     gettextinfo (&t_info);
  1818.     if (t_info.currmode == C40 || t_info.currmode == C80)
  1819.     {
  1820.         dispmode = COLOR;
  1821.         header->fore = YELLOW;
  1822.         header->back = MAGENTA;
  1823.         header->hifore = YELLOW;
  1824.         header->hiback = RED;
  1825.         header->bstyle = DOUBLE;
  1826.         header->bcolor = LIGHTGRAY;
  1827.         header->shadow = ON;
  1828.         center->fore = WHITE;
  1829.         center->back = CYAN;
  1830.         center->hifore = YELLOW;
  1831.         center->hiback = RED;
  1832.         center->bstyle = DOUBLE;
  1833.         center->bcolor = DARKGRAY;
  1834.         center->shadow = ON;
  1835.         bottom->fore = BLACK;
  1836.         bottom->back = GREEN;
  1837.         bottom->hifore = WHITE;
  1838.         bottom->hiback = RED;
  1839.         bottom->bstyle = DOUBLE;
  1840.         bottom->bcolor = DARKGRAY;
  1841.         bottom->shadow = ON;
  1842.     }
  1843.     else
  1844.     {
  1845.         dispmode = BW;
  1846.         header->fore = LIGHTGRAY;
  1847.         header->back = BLACK;
  1848.         header->hifore = LIGHTGRAY;
  1849.         header->hiback = BLACK;
  1850.         header->bstyle = DOUBLE;
  1851.         header->bcolor = LIGHTGRAY;
  1852.         header->shadow = OFF;
  1853.         center->fore = LIGHTGRAY;
  1854.         center->back = BLACK;
  1855.         center->hifore = LIGHTGRAY;
  1856.         center->hiback = BLACK;
  1857.         center->bstyle = DOUBLE;
  1858.         center->bcolor = LIGHTGRAY;
  1859.         center->shadow = OFF;
  1860.         bottom->fore = LIGHTGRAY;
  1861.         bottom->back = BLACK;
  1862.         bottom->hifore = LIGHTGRAY;
  1863.         bottom->hiback = BLACK;
  1864.         bottom->bstyle = DOUBLE;
  1865.         bottom->bcolor = LIGHTGRAY;
  1866.         bottom->shadow = OFF;
  1867.     }
  1868.     return (dispmode);
  1869. }
  1870.  
  1871.  
  1872.  
  1873. void clear_status (WININFO *win)
  1874. {
  1875.     textattr (win->fore + (win->back << 4));
  1876.     gotoxy (1,1);
  1877.     clreol();
  1878. }
  1879.  
  1880.  
  1881. /**********************************************************************
  1882. *  the following code comes from DOSWDW by Edward V. Dong, a Turbo C  *
  1883. *  implementation of EXECWINDOW by Kim Kokkonen, TurboPower Software, *
  1884. *  which was released to the public domain.                           *
  1885. **********************************************************************/
  1886. void far DoDosWdw(int xleft,int ytop,int xrite,int ybottom,int attrib,char *cmd)
  1887. {
  1888.     textattr(attrib);                       /* set text attribute */
  1889.     window(xleft, ytop, xrite, ybottom);    /* make the window */
  1890.     clrscr();                               /* clear the window */
  1891.     wdwpos = ((ytop - 1) * 256) + (xleft - 1);
  1892.     wdwupr = wdwpos;
  1893.     wdwlwr = ((ybottom - 1) * 256) + (xrite - 1);
  1894.     wdwattr = (attrib);
  1895.     oldint21 = getvect(0x21);       /* save old interrupt 21h */
  1896.     setup21(0);            /* move vector into CS (use 0 to scroll screen) */
  1897.     setvect(0x21, newint21);    /* point to dos window */
  1898.     system(cmd);            /* run the command */
  1899.     setvect(0x21, oldint21);    /* restore interrupt 21h */
  1900. }
  1901.